<template>
  <Layout>
    <div>
    <el-row class="el-row">
      <div class="el-col">
        <el-select filterable :filter-method="filter" v-model="chartPkId" placeholder="" size="small" style="width: 150px"  @click="addGoodsHistory()">
          <el-option v-if="fileData" :key="fileName" :label="fileName" :value="fileName" disabled>
            <span>{{fileName}}</span>
          </el-option>
          <div v-for="{goods,pkId,collect} in filterGoodList" class="option_item">
            <el-option :key="pkId" :label="goods" :value="pkId" class="option_text">
              <span>{{ goods }}</span>
            </el-option>
            <span  @click="goodUp(pkId)" class="option_icon" >
              <el-icon v-if="!collect" class="option_icon_start"><Star /></el-icon>
              <el-icon v-else color="#F2E209" size="20" class="option_icon_start_filled"><StarFilled /></el-icon>
            </span>
          </div>
          <template #footer>
            <el-button type="primary" size="small" @click="openCSVFile()">
              读取CSV文件
          </el-button>
          </template>
          <!-- <el-option-group key="读取" label="文件" disabled>
            <el-option key="pkId" label="goods" value="pkId" class="option_text"></el-option>
          </el-option-group> -->
        </el-select>
      </div>
      <div class="el-col" >
        <el-radio-group v-model="period" size="small">
          <el-radio-button v-for=" {name,type} in filterPeriods" :key="type" :label="name" :value="type" :disabled="disable"></el-radio-button>
        </el-radio-group>
      </div>
      <div class="el-col">
        <el-button-group>
          <el-color-picker v-model="overlayColor" size="small" :predefine="predefineColors" :disabled="disable" @focus="colorPickerFocusEvent()"/>
          <el-dropdown split-button size="small" @click="!!currentBrush && setOverlayType(currentBrush.key)">
                <div v-if="!!currentBrush" v-html="currentBrush.svg+' '+currentBrush.text" style="display: flex;line-height:26px;height:100%;width:100%;"></div > 
                <span v-else style="display: flex;">画图工具</span> 
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item 
                v-for="{ svg , key , text } in overlays"
                :key="key"
                v-on:click="setOverlayType(key)"
                >
                <div v-html="svg+' '+text" style="display: flex; font-size:13px; line-height:25px;"></div> 
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <el-dropdown  :disabled="disable" trigger="click"  @click="!!currentBrushText && setRectText(currentBrushText)"  @visible-change="getTexts()" split-button size="small" >
            <div style="display: flex;line-height:26px;height:100%;width:100%;">
              {{currentBrushText || '快捷注释'}}
              <!-- <el-icon class="el-icon--right"><arrow-down /></el-icon> -->
            </div>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item 
                v-for="text in texts"
                :key="text"
                @click="setRectText(text)"
                >
                {{text}}
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-button-group>
      </div>

      <div class="el-col">
        <el-button-group>
          <el-button size="small" type="primary" @click="save()" :disabled="disable">
            <el-icon><Checked /></el-icon>
          </el-button>
          <el-button size="small" type="primary" @click="removeAll()" :disabled="disable">
            <el-icon><DeleteFilled /></el-icon>
          </el-button>
          <el-button size="small" type="primary" @click="openStoreList()" :disabled="disable">
            <el-icon><List /></el-icon>
          </el-button>
          <el-select v-model="currentStore" placeholder="" clearable size="small" style="width: 100px"  @click="overlaysClickEvent()" :disabled="disable">
            <div v-for="{ id,storeName } in overlayStores" class="option_item">
            <span>
              <el-icon :color="!!overlayLayers.find(v => v == storeName)?'#79bbff':'#f89898'"  @click="switchLayerStatus(storeName)"  class="el-icon-close">
                <View v-show="!!overlayLayers.find(v => v == storeName)"/><Hide v-show="!overlayLayers.find(v => v == storeName)"/>
              </el-icon>
            </span>
              <el-option :key="storeName"  :label="storeName" :value="storeName" class="option_text" size="small">
                <div>
                  <span class="store_name">{{storeName}}</span>
                </div>
              </el-option>
              <span>
                <el-icon @click="removeStoreItem(storeName)" class="el-icon-close"><CircleCloseFilled/></el-icon>
              </span>
            </div>
          </el-select>
          <!-- <el-dropdown  trigger="click">
            <el-button size="small" type="primary" @click="overlaysClickEvent()" :disabled="disable">
              <el-icon><List /></el-icon><el-icon class="el-icon--right"><arrow-down /></el-icon>
            </el-button>
            <template #dropdown>
              <el-dropdown-item 
                v-for="{ storeName } in overlayStores"
                :key="storeName"
              >
                <div  @click="switchLayerStatus(storeName)" style="flex:1;">
                  <el-icon :color="!!overlayLayers.find(v => v == storeName)?'#79bbff':'#f89898'" >
                    <View v-show="!!overlayLayers.find(v => v == storeName)" /><Hide v-show="!overlayLayers.find(v => v == storeName)"/>
                  </el-icon>
                  <span class="store_name">{{storeName}}</span>
                </div>
                <el-icon @click="removeStoreItem(storeName)" class="el-icon-close"><CircleCloseFilled /></el-icon>
              </el-dropdown-item>
            </template>
          </el-dropdown> -->
        </el-button-group>
      </div>
    </el-row>
  </div>
  <div v-loading="loading" :id="chartId" class="k-line-chart" ref="chart"/>
  <el-dialog v-model="openModify" width="250px" title="修改颜色" :close-on-click-modal="false">
    <el-form label-width="auto">
      <el-form-item label="修改颜色">
        <el-color-picker v-model="ModifyOverlayColor" size="small" :predefine="predefineColors" @focus="colorPickerFocusEvent()"/>
      </el-form-item>
    </el-form>
  </el-dialog>
  <!-- <historyDialog id="save_note_history" v-model:show="nodeHistoryShow" title="请输入笔记的名称" @save="save($event)" @cancel="nodeHistoryShow = false"></historyDialog> -->
  <historyDialog id="save_text_history" v-model:show="textHistoryShow" title="请输入用于注释的文本" @save="setRectText($event)" @cancel="textHistoryShow = false"></historyDialog>
  </Layout>
</template>

<script>
import { dispose, init,setXAxisImpZone,getOverlayById} from "klinecharts";
import { mapActions } from 'pinia';
import { crosshair,charts,currentChartId } from '../../store.js'
import Layout from "./Layout.vue";
import { ElMessageBox,ElMessage } from 'element-plus'
import { getAllGoods,getKLinefromGoods,getNewKLinefromGoods,getKLinefromGoodsfromN } from '../../apis.js'
import '../../klinechartOverlay.js'
import { nanoid } from 'nanoid'
import localStore from '../../localStore.js'
import svgs from '../../assets/svgList.js'
import historyDialog from '../historyDialog.vue'
import store from "../../localStore.js";


export default {
  name: "ChartOverlay",
  components: { Layout,historyDialog },
  props:{
    id:{type:String,default:() => (`chart_${Math.ceil(Math.random() * 999999)}`)},
    union:{type:Boolean,default:false},
    timezone:{type:String},
    syncOverlayColor:{type:String},
    open:{type:Boolean},
    switchOverlay:{type:Object},
  },
  data: function () {
    return {
      overlays: [
        { key: "straightLine" ,text : "延长线"}, 
        { key: "segment" ,text : "线段"}, 
        { key: "horizontalSegment" ,text : "水平线段"}, 
        { key: "rayLine" ,text :" 射线"},
        { key: "parallelStraightLine" ,text : "平行线"},
        { key: "fibonacciLine" ,text : "斐波那切线"}, 
        { key: "infoLine", text: "信息线" },
        { key: "rect", text: "矩形" },
        { key: "hollowrect", text: "空心矩形" },
        // { key: "tris", text: "三角形" },
        { key: "ABCD", text: "三角形" },
        { key: "sevPoints", text: "头肩" },
        { key: "XABCD", text: "XABCD" },
        {key:'rectText',text:'注释'}, 
      ],
      overlayStores:[],
      periods:[
        {name:'M1',type:'M1'},
        {name:'M5',type:'M5'},
        {name:'M15',type:'M15'},
        {name:'M30',type:'M30'},
        {name:'H1',type:'H1'},
        {name:'H4',type:'H4'},
        {name:'D1',type:'D1'},
        {name:'W1',type:'W1'},
        {name:'MN',type:'MN'},
      ],
      period:'M1',
      chartPkId: undefined,
      goodList:[],
      chart: undefined,
      loading:false,
      updateId: undefined,
      overlayIds:[], //用于存储当前覆盖物id
      LineList:[], //当前的k线数据
      isLoadMore:false, //用于防止常态更新与追加冲突
      predefineColors:[
        '#ffffff',
        '#1677ff',
        '#4a148c',
        '#e53935',
        '#dce775',
        '#233d40',
        '#d19640',
        '#178578',
      ],
      currentBrush:undefined, //当前的画笔
      currentBrushText:undefined, //当前的快捷注释
      overlayColor: '#FFFFFF',
      volFlg: false, //判断交易量是否开启，防止重复开启
      nodeHistoryShow: false, //用于开启保存历史弹窗
      textHistoryShow: false, //用于开启注释文本弹窗
      goodFilter: '', //用于筛选条件
      fileData:undefined, //文件内容
      fileName:undefined, //文件名称
      preload:false, //用于判断是否已经预加载,
      texts:[],//快捷注释
      currentStore:undefined,//当前选中的图层
      selectOverlayId:undefined, //当前被选中的覆盖物
      ModifyOverlayColor:'', //当前被选中的覆盖物的颜色
      openModify:false //用于打开修改颜色的浮层
      
    };
  },
  mounted: async function () {
    //添加svgs
    this.overlays.forEach(v => {v.svg = svgs[v.key] || ''});
    //获取品种列表
    let goodsInfo = await getAllGoods();
    this.goodList = goodsInfo.data.data;
    //预加载
    if(localStore.getItem(`chartPreload_${this.id}_goods`) || localStore.getItem(`chartPreload_${this.id}_period`)){
      this.chartPkId = parseInt(localStore.getItem(`chartPreload_${this.id}_goods`));
      this.period =  localStore.getItem(`chartPreload_${this.id}_period`) || 'M1';
      this.$nextTick(() => {this.createChart();this.preload = true;});
    }
    else{
      this.$nextTick(() => {this.preload = true;});
    }
    this.colorPickerFocusEvent();
    this.overlayColor = localStore.getItem('overlay_color');
  },
  computed:{
    filterPeriods(){
      if(!this.fileData){
        return this.periods;
      }
      else if(this.fileData){
        //单周期
        return [];
      }
    },
    filterGoodList(){
      return this.goodList.filter(v => v.goods.toLocaleLowerCase().indexOf(this.goodFilter.toLocaleLowerCase()) >= 0);
    },
    disable(){
      if(typeof this.chartPkId == 'undefined' || this.chartPkId == null){
        return  true;
      }
      else{
        return false;
      }
    },
    chartId(){
    return `${this.id}_pkid`;
    },
    overlayLayers(){
      let layers = new Array(...(new Set(this.overlayIds.map(v => v.from))));
      return layers;
    },
    saveId(){
      // return `overvaly_${this.chartPkId}_${this.period}`;
      // return 'default_new';
      return 'overlays_default_new';
    },
  },
  watch:{
    ModifyOverlayColor(newColor,oldColor){
      if(this.openModify){
        //打开了修改颜色
        if(this.selectOverlayId){
          let currentOverlay = this.chart.getOverlayById(this.selectOverlayId);
          if(currentOverlay.styles.arc.color == newColor){
            
          }
          else {
            //修改了颜色
            currentOverlay.setStyles({
              point:{color:newColor,activeColor:newColor},
              line:{color:newColor},
              rect:{color:`${newColor}7f`,borderColor:newColor},
              polygon:{color:`${newColor}7f`,borderColor:newColor},
              circle:{color:`${newColor}7f`,borderColor:newColor},
              arc:{color:newColor,borderColor:newColor},
              text:{color:newColor,}
            });
            window.currentOverlay = currentOverlay;
          }
        }
      }
    },
    switchOverlay(newVal){
      if(!!newVal && !!newVal.action){
        //通信
        //action remove add
        //storeName
        if(newVal.action == 'remove'){
          this.overlaysClickEvent(true);
        }
        else if(newVal.action == 'add'){
          this.overlaysClickEvent();
          this.$nextTick(() =>{
            this.switchLayerStatus(newVal.storeName);
            this.currentStore = newVal.storeName;
          });
        }
        else if(newVal.action == 'update'){
          let possibleStores = newVal.possibleStores;
          this.overlaysClickEvent();
          possibleStores.forEach(possibleStore => {
            if(this.overlayLayers.find(v => v == possibleStore)){
                this.switchLayerStatus(possibleStore);
                this.switchLayerStatus(possibleStore);
            }
          })
        }
      }
    },
    open(){
      if(this.chart){
        this.chart._xAxisPane.getAxisComponent().buildTicks(true);
        this.chart.updatePane(4);
      }
    },
    filterPeriods(newFilterPeriods,oldFilterPeriods){
    if(newFilterPeriods.length > 0){
      return this.period = newFilterPeriods[0].type;
    }
    else{
      return null;
    }
    },
    syncOverlayColor(newColor,oldColor){
      this.overlayColor = newColor;
    },
    overlayColor(newColor,oldColor){
      if(!newColor){
        this.overlayColor = '#1677ff'; //默认值
      }
      else{
        if(!this.predefineColors.find(color => color.toLocaleUpperCase() == newColor.toLocaleUpperCase())){
          let newPredefineColors = JSON.parse(JSON.stringify(this.predefineColors));
          newPredefineColors.pop();
          newPredefineColors.unshift(newColor);
          localStore.setItem('predefineColors',JSON.stringify(newPredefineColors));
          this.colorPickerFocusEvent();
        }
      }
      this.$emit('overlayColorChange',newColor);
      localStore.setItem('overlay_color',newColor);
    },
    chartPkId(newId,oldId){
      if(!this.preload) return;
      //切换品种
      this.LineList = [];
      this.currentStore = undefined;
      if(oldId){
        this.removeChart(oldId);
        this.removeAllOverlay();
      }
      if(newId == this.fileName){
        //从文件中读取的
        this.$nextTick(() => {this.createChart({type:'file'});});
      }
      else{
        this.fileName = undefined;
        this.fileData = undefined;
        this.$nextTick(() => {this.createChart();});
      }
      //保存品种
      if(this.chartPkId != this.fileName){
        localStore.setItem(`chartPreload_${this.id}_goods`,newId);
      }
    },
    period(newStep,oldStep){
      if(!this.preload) return;
      //切换周期
      this.LineList = [];
      this.currentStore = undefined;
      if(oldStep){
        this.removeChart();
        this.removeAllOverlay();
      }
      if(this.chartPkId == this.fileName){
        //从文件中读取的
        this.$nextTick(() => {this.createChart({type:'file'});});
      }
      else{
        this.$nextTick(() => {this.createChart({period:newStep});});
      }
      //保存周期
      if(this.chartPkId != this.fileName){
        localStore.setItem(`chartPreload_${this.id}_period`,newStep);
      }
    },
    timezone(newZone,oldZone){
      if(this.chart){
        this.$nextTick(() => {this.chart.setTimezone(this.timezone)});
      }
    }
  },
  methods: {
    ...mapActions(crosshair,{setCrosshair:'set'}),
    ...mapActions(charts,{addCharts:'add',removeCharts:'remove'}),
    ...mapActions(currentChartId,{setCurrentChartId:'set'}),
    colorPickerFocusEvent(e){
      if(localStore.getItem('predefineColors')){
        this.predefineColors = JSON.parse(localStore.getItem('predefineColors'));
      }
      else{
        localStore.setItem('predefineColors',JSON.stringify(this.predefineColors));
      }
    },
    setOverlayType: function (name) {
      this.currentBrush = this.overlays.find(v => v.key == name); 
      if(name == 'rect' || name == 'straightLine'){
        this.createOverlay({overlayOpts:{name}});
      }
      else if(name == 'rectText'){
        this.textHistoryShow = true;
      }
      else{
        this.createOverlay({overlayOpts:{name}});
      }
    },
    setRectText(text){
      this.currentBrushText = text;
      this.createOverlay({overlayOpts:{name:'rectText',extendData:text}});
    },
    removeAllOverlay() {
      this.overlayIds = [];
      if(this.chart)this.chart.removeOverlay();
    },
    addAllOverlay(name){
      if(name == '' || !name){
        ElMessage({
          message: '名称不能为空',
          type: 'warning',
        });
        return;
      }
      const overlays =  this.chart._chartStore._overlayStore._instances;
      let overlaysInfoList = [];
      overlays.forEach(v => v.forEach(overlay => {
        overlaysInfoList.push({
          id: overlay.id,
          name: overlay.name,
          points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value,dataIndex:v.dataIndex})),
          // points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value})),
          extendData: overlay.extendData,
          styles:overlay.styles
        })
      }))
      if(this.getOverlayStores({type:'all'}).find(store => store.storeName == name)){
        //名称存在
        ElMessage({
          message: '保存失败，名称已存在',
          type: 'error',
        });
      }
      else{
        overlaysInfoList = overlaysInfoList.filter(v => {
          return !!this.overlayIds.find(overlayId => overlayId.id == v.id && overlayId.from == '' )
        });
        overlaysInfoList = overlaysInfoList.map(v => ({...v,id:undefined}));
        if(overlaysInfoList.length == 0){
          ElMessage({
            message: '可用于保存的覆盖物数量为零，保存失败',
            type: 'error',
          });
          return;
        }
        this.overlayIds = this.overlayIds.map(v => ({...v,from:(v.from == '' ? name : v.from)}));
        let overlayStores = this.getOverlayStores({type:'all'});
        let storeId = nanoid();
        overlayStores.push({
          id:storeId,
          storeName: name,
          overlays: overlaysInfoList,
          depends:[
            {
              pkId:this.chartPkId,
              goods:this.goodList.find(v => v.pkId == this.chartPkId).goods,
              period:this.period,
            }
          ],
          originDepend:{
            pkId:this.chartPkId,
            goods:this.goodList.find(v => v.pkId == this.chartPkId).goods,
            period:this.period,
          }
        });
        localStore.setItem(this.saveId,JSON.stringify(overlayStores));
        this.$nextTick(() => {
          this.currentStore = name;
        });
        ElMessage({
          message: '保存成功',
          type: 'success',
        });
        // return storeId;
      }
    },
    overOldOverlay(name){
      const overlays =  this.chart._chartStore._overlayStore._instances;
      let overlaysInfoList = [];
      overlays.forEach(v => v.forEach(overlay => {
        overlaysInfoList.push({
          id: overlay.id,
          name: overlay.name,
          points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value,dataIndex:v.dataIndex})),
          // points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value})),
          extendData: overlay.extendData,
          styles:overlay.styles
        })
      }));
      overlaysInfoList = overlaysInfoList.filter(v => {
        return !!this.overlayIds.find(overlayId => overlayId.id == v.id && overlayId.from == '' ) || !!this.overlayIds.find(overlayId => overlayId.id == v.id && overlayId.from == name )
      });
      overlaysInfoList = overlaysInfoList.map(v => ({...v,id:undefined}));
      this.overlayIds = this.overlayIds.map(v => {if(!v.from){return {...v,from:name}}else{return  v}});
      let overlayStores = this.getOverlayStores({type:'all'});
      overlayStores.forEach((store,i,arr) => {
        if(store.storeName == name){
          store.overlays = overlaysInfoList
        }
      })
      localStore.setItem(this.saveId,JSON.stringify(overlayStores));
      ElMessage({
        message: '覆盖成功',
        type: 'success',
      });
    },
    save(){
      if(this.currentStore){
        let overlayStore = this.getOverlayStores({type:'all'});
        let currentOverlay = overlayStore.find(overlay => overlay.storeName == this.currentStore);
        if(currentOverlay.lock){
          ElMessage({
            message: '该笔记已经被锁定，无法覆盖',
            type: 'warning',
          });
        }
        else{
          ElMessageBox.confirm(`确认覆盖 （${this.currentStore}） 笔记?`,'',{
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            showCancelButton: false	
          })
          .then(() => {
            this.overOldOverlay(this.currentStore);
          })
          .catch(() => {})
        }
      }
      else{
        this.$prompt('请输入笔记名称', '请输入笔记名称', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
        }).then(({value}) => {
          this.addAllOverlay(value);
        }).catch(e => {})
      }

    },
    removeAll(){
      this.removeAllOverlay();
        ElMessage({
          message: '删除成功',
          type: 'success',
        });
    },
    restoreOverlays(name){
        let overlays = this.getOverlayStores().find( store => store.storeName == name).overlays;
        
        if(Array.isArray(overlays)){
          overlays.forEach(overlay => {
            this.createOverlay({overlayOpts:overlay,from:name});
          })
        }
    },
    removeStoreItem(name){
      ElMessageBox.confirm(`确认取消挂载 （${name}） 笔记?`,'',{
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        showCancelButton: false	
      })
      .then(() => {
        let overlayStore = this.getOverlayStores({type:'all'});
        overlayStore.forEach(store => {
          if(store.storeName == name){
            store.depends = store.depends.filter( dep => !(dep.pkId == this.chartPkId && dep.period == this.period));
          }
        });
        // let newOverlayStores = this.getOverlayStores().filter( store => store.storeName != name);
        localStore.setItem(this.saveId,JSON.stringify(overlayStore));
        this.overlaysClickEvent(true);
        ElMessage({
          message: `（${name}） 笔记取消挂载成功`,
          type: 'success',
        });
      })
      .catch(() => {})
    },
    async createChart(opts){
      this.chart = init(this.chartId,{});
      this.chart.setLocale('zh-CN'); //设置为中文
      this.chart.setTimezone(this.timezone); //设置时区
      this.chart.setPriceVolumePrecision(4); //设置价格精度
      this.chart.setStyles({
        grid: {
          show: true,
          horizontal: {
            // color:'#434447',
            color:'#3B3C3E',
          },
          vertical: {
            show: true,
            size: 1,
            color: '#FFFFFF',
            style: 'dashed',
            dashedValue: [2, 2]
          }
        },
        candle:{
          bar:{
            upColor: '#F92855',
            downColor: '#2DC08E',
            upBorderColor: '#F92855',
            downBorderColor: '#2DC08E',
            upWickColor: '#F92855',
            downWickColor: '#2DC08E',
          },
          tooltip: {
            text: {
              color: '#FFFFFF',
            },
          },
          priceMark: {
              high: {
                show: true,
                // color: '#FFFFFF',
                color: 'transparent',
              },
              // 最低价标记
              low: {
                show: true,
                // color: '#FFFFFF',
                color: 'transparent',
              },
          }
        },
        xAxis:{
          // // x轴线
          // axisLine: {
          //   color: '#888888',
          // },
          // x轴分割文字
          tickText: {
            color: '#FFFFFF',
          },
        },
        yAxis:{
          tickText: {
            color: '#FFFFFF',
          },
        },
        indicator: {
          ohlc: {
            upColor: 'rgba(249, 40, 85, .7)',
            downColor: 'rgba(45, 192, 142, .7)',
          },
          bars: [{
            upColor: 'rgba(249, 40, 85, .7)',
            downColor: 'rgba(45, 192, 142, .7)',
          }],
          tooltip: {
            text: {
              color: '#FFFFFF',
            },
          }
        }
      }); //设置价格精度
      //清除定时器
      if(this.updateId){
        clearTimeout(this.updateId);
        this.updateId = undefined;
      }
      if(!this.volFlg){
        this.chart.createIndicator({name:'VOL',isStack:true}); //开启交易量
        this.volFlg = true;
      }
      // this.chart.setOffsetRightDistance(0);
      //判断是不是从文件中读取的
      if(opts && opts.type == 'file'){
        this.loading = true;
        this.LineList = this.fileData;
        this.chart.applyNewData(this.LineList);
        this.loading = false;
      }
      else{
        //获取数据
        this.loading = true;
        const goods = this.goodList.find(v => v.pkId == this.chartPkId).goods;
        const period = this.period;
        let {zone,kLine:LineList} = await getKLinefromGoodsfromN({goods,period:this.period,n:1});
        setXAxisImpZone(zone);
        //判断是否切换了周期或者品种或者读取了文件,如果是取消执行
        if(!!this.fileData || goods != this.goodList.find(v => v.pkId == this.chartPkId).goods || period != this.period) {
          clearTimeout(this.updateId);
          return;
        }
        this.LineList = LineList;
        this.chart.applyNewData(LineList);
        this.loading = false;
        //启动更新
        this.updateChart();
        //设置向后加载
        this.chart.loadMore(async (timestamp) => {
          if(this.fileData) return; // 读取文件数据源 ,停止追加功能
          if(this.isLoadMore) return; //正在追加，防止重复执行
          this.isLoadMore = true; //开启追加状态，防止冲突
          const goods = this.goodList.find(v => v.pkId == this.chartPkId).goods;
          let oldLineId = this.LineList[0].pkId;
          let newLineList = await getKLinefromGoods({goods,period:this.period,lineId:oldLineId});
          newLineList = newLineList.filter(v => v.pkId != oldLineId);
          newLineList.sort((aLine,bLine) => (new Date(aLine.timestamp) > new Date(bLine.timestamp) ? 1 : -1));
          this.chart.applyMoreData(newLineList,true)
          let LineList = [...newLineList, ...this.LineList];
          LineList.sort((aLine,bLine) => (new Date(aLine.timestamp) > new Date(bLine.timestamp) ? 1 : -1));
          this.LineList = LineList;
          this.isLoadMore = false; //关闭追加状态
        })
      }

      if(this.union){
        //联动
        this.addCharts(this.chart);
        this.chart.onHandviorMoused = (crosshair) => {
        //获取point对应的时间等数据
        if(crosshair){
          crosshair = this.chart.getChartStore().getCrosshairStore().getData(crosshair);
        }
          this.setCrosshair(crosshair);
          this.setCurrentChartId(this.chart.id)
        };
      }
      //读取历史笔记
      // this.restoreOverlays();
      if(localStore.getItem(this.saveId)){
        this.getOverlayStores();
        //读取覆盖物
        this.overlaysClickEvent();
        this.$nextTick(() => {
          this.overlayStores.forEach(store => {
            this.switchLayerStatus(store.storeName);
          });
        });
      }
      else{
        localStore.setItem(this.saveId,JSON.stringify([]));
      }

    //添加监听Dom变化
    const myObserver = new ResizeObserver((entries) => {
      entries.forEach((entry) => {
        this.chart.adjustPaneViewport(true, true, true, true, true);
      })
    })
    myObserver.observe(this.$refs.chart);
    },
    removeChart(oldId){
      if(this.union) this.removeCharts(this.chart);
    },
    updateChart(){
      this.updateId = setTimeout(async () =>{
        const goods = this.goodList.find(v => v.pkId == this.chartPkId).goods;
        let currentPkId = this.chartPkId;
        let period = this.period;
        let oldLineId = this.LineList[this.LineList.length - 1].pkId;
        let appendLineList = await getNewKLinefromGoods({goods,period:this.period,lineId:oldLineId});
        //已经切换品种或周期，取消
        if(currentPkId != this.chartPkId || period != this.period) return;
        //追加历史数据中，更新滞后
        if(this.isLoadMore) return;
        if(appendLineList.length > 1){
          //更新以及追加
          this.chart.updateData(appendLineList.find(v => v.pkId == oldLineId));
          let moreDataList = appendLineList.filter(v => v.pkId != oldLineId);
          moreDataList.sort((aLine,bLine) => (new Date(aLine.timestamp) > new Date(bLine.timestamp) ? 1 : -1));
          moreDataList.forEach(v => this.chart.updateData(v));
          // this.chart.applyMoreData(moreDataList);
        }
        else if(appendLineList.length == 1){
          //更新
          this.chart.updateData(appendLineList[0]);
        }
        //重新缓存数据
        let LineList = [...this.LineList.filter(v => v.pkId != oldLineId),...appendLineList];
        LineList.sort((aLine,bLine) => (new Date(aLine.timestamp) > new Date(bLine.timestamp) ? 1 : -1));
        this.LineList = LineList;

        //再次执行
        this.updateChart();
      },600);
    },
    getOverlayStores(opts){
      if(opts && opts.type == 'all'){
        return JSON.parse(localStore.getItem(this.saveId));
      }
      let overlays = JSON.parse(localStore.getItem(this.saveId));
      overlays = overlays.filter(overlay => {
        if(!!overlay.depends){
          let depends = overlay.depends;
          if(!!depends.find(dep => (dep.pkId ==  this.chartPkId && dep.period == this.period))){
            return true;
          }
          else{
            return false;
          }
        }
        return false;
      })
      return overlays;
    },
    getGoodsHistory(){
      let goods_history = localStore.getItem('goods_history');
      let history;
      if(!goods_history){
        this.setGoodsHistory([]);
        history = [];
      }
      else{
        history = JSON.parse(goods_history);
      }
      return history;
    },
    setGoodsHistory(history){
      localStore.setItem('goods_history',JSON.stringify(history));
    },
    overlaysClickEvent(flag){
      this.overlayStores = this.getOverlayStores();
      if(flag){
        let froms = Array(...(new Set(this.overlayIds.map(v => v.from).filter(v => v != ''))));
        froms.forEach(from => {
          if(!this.overlayStores.find(store => store.storeName == from)){
            this.switchLayerStatus(from);
            if(from == this.currentStore){
              this.currentStore = undefined;
            }
          }
        });
        if(!this.overlayStores.find(store => store.storeName == this.currentStore) && this.currentStore){
          this.currentStore = undefined
        }
      }
    },
    clearLayerStatus(){
      //获取目前的全部覆盖物参数     
      const overlays =  this.chart._chartStore._overlayStore._instances;
      let overlaysInfoList = [];
      overlays.forEach(v => v.forEach(overlay => {
        overlaysInfoList.push({
          overlayOpts:{
            name: overlay.name,
            points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value,dataIndex:v.dataIndex})),
            extendData: overlay.extendData,
            styles:overlay.styles
          },
          from: this.overlayIds.find(v1 => v1.id == overlay.id).from
        })
      }));
      overlaysInfoList = overlaysInfoList.filter(v => !v.from);
      this.removeAllOverlay();
      overlaysInfoList.forEach(v => {
        this.createOverlay({overlayOpts:v.overlayOpts,from:v.from});
      })
    },
    switchLayerStatus(name){ 
      //获取目前的全部覆盖物参数     
      const overlays =  this.chart._chartStore._overlayStore._instances;
      let overlaysInfoList = [];
      overlays.forEach(v => v.forEach(overlay => {
        overlaysInfoList.push({
          overlayOpts:{
            name: overlay.name,
            points: overlay.points.map(v => ({timestamp:v.timestamp,value:v.value,dataIndex:v.dataIndex})),
            extendData: overlay.extendData,
            styles:overlay.styles
          },
          from: this.overlayIds.find(v1 => v1.id == overlay.id).from
        })
      }));
      
      if(this.overlayLayers.find(v => v == name)){
        //已存在，清除
        overlaysInfoList = overlaysInfoList.filter(v => v.from != name);
        this.removeAllOverlay();
        overlaysInfoList.forEach(v => {
          this.createOverlay({overlayOpts:v.overlayOpts,from:v.from});
        })
      }
      else{
        //生成覆盖物
        try{
          this.restoreOverlays(name);
          // if(!!this.overlayLayers.find(v => v == name)){
          //   ElMessage({
          //     message: '读取成功',
          //     type: 'success',
          //   }); 
          // }
        }
        catch(e){
          ElMessage({
            message: '读取失败',
            type: 'error',
          });
        }
      }
    },
    createOverlay({overlayOpts,from = ''}){
      let overlayColor = `${this.overlayColor}`;
      if(overlayOpts && overlayOpts.points)
      {
        //笔记
        //用于不同周期使用同一个笔记的问题处理
        overlayOpts.points.forEach(point => {
          let filter = this.LineList.filter(v => v.timestamp == point.timestamp);
          if(filter.length == 0){
            //不存在
            if(point.timestamp >= this.LineList[this.LineList.length - 1].timestamp){
              point.timestamp = this.LineList[this.LineList.length - 1].timestamp;
            }
            else if(point.timestamp <= this.LineList[0].timestamp){
              return;
            }
            else{
              let findTime = this.LineList.find((v,i,arr) => {
                if(i == arr.length - 1){
                  return true;
                }
                else if(arr[i].timestamp <= point.timestamp && arr[i + 1].timestamp >= point.timestamp){
                  return true;
                }
              });
              point.timestamp = findTime.timestamp;
            }
          }
        });
      }
      let overlayId =  this.chart.createOverlay(
      {
        onRemoved:(e) => {
          //e.overlay.id
          let overlay = this.overlayIds.find(v => v.id == e.overlay.id);
          if(!!overlay){
            //存在
            let layerName = overlay.from;
            this.overlayIds = this.overlayIds.filter(overlayInfo => overlayInfo.id != e.overlay.id);
          }
        },
        // onSelected:(e) => {
        //   console.log('selected');
        //   this.selectOverlayId = e.overlay.id;
        // },
        // onDeselected:(e) => {
        //   this.selectOverlayId = undefined;
        // },
        onClick:(e) => {
          // console.log('click');
          if(e.overlay.oldClickTimeStamp && Date.now() - e.overlay.oldClickTimeStamp <= 1000){
            //双击
            // console.log('doubleClick');
            console.log(e);
            this.selectOverlayId = e.overlay.id;
            this.ModifyOverlayColor = e.overlay.styles.arc.color;
            this.$nextTick(() => {
              this.openModify = true;
            })
          }
          e.overlay.oldClickTimeStamp = Date.now();
        },
        styles:{
          point:{color:overlayColor,activeColor:overlayColor},
          line:{color:overlayColor},
          rect:{color:`${overlayColor}7f`,borderColor:overlayColor},
          polygon:{color:`${overlayColor}7f`,borderColor:overlayColor},
          circle:{color:`${overlayColor}7f`,borderColor:overlayColor},
          arc:{color:overlayColor,borderColor:overlayColor},
          text:{color:overlayColor,},
        },
        ...overlayOpts,
      });
      this.overlayIds.push({id:overlayId,from,overlayOpts});
    },
    addGoodsHistory(){
      let history = this.getGoodsHistory() || [];
      this.goodList = this.goodList.map(v => (history.indexOf(v.pkId) >= 0 ?{...v,collect:true}:{...v,collect:false}));
      this.goodList = this.goodList.sort((good1,good2) => {
        if(good1.collect && !good2.collect){
          return -1;
        }
        else if(!good1.collect && good2.collect){
          return 1;
        }
        else if(good1.collect && good2.collect){
          return history.indexOf(good1.pkId) - history.indexOf(good2.pkId);
        }
        else{
          return 0;
        }
      });
    },
    goodUp(pkId){
      let history = this.getGoodsHistory();
      if(history.indexOf(pkId) >= 0){
        history = history.filter(v => v != pkId);
      }
      else{
        history.push(pkId);
      }
      this.setGoodsHistory(history);
      this.addGoodsHistory();
    },
    filter(filterStr){
      this.goodFilter = filterStr;
    },
    async openCSVFile(){
      let result;
      if(window.electron){
        result = await window.electron.openCSV();
      }
      else{
        ElMessage({
            message: '暂不支持',
            type: 'error',
        });
        return;
      }
      let {canceled,filePaths,csvFile:{data}} = result;
      if(canceled) return;
      let name = filePaths[0].split('\\');
      this.fileName = name[name.length - 1];
      this.chartPkId = name[name.length - 1];
      let len = data.length;
      data = data.filter(v => ((v.timestamp || v.time) && v.open && v.high && v.low && v.close && v.vol));
      if(data.length == 0){
        ElMessage({
            message: '请检查csv文件的格式',
            type: 'error',
          });
          return;
      }
      else if(data.length < len){
        ElMessage({
            message: '部分数据不符合，已被剔除',
            type: 'waring',
          });
      }
      data = data.map(v => ({...v,timestamp: new Date(v.timestamp || v.time).getTime(), volume: v.vol }));
      data.sort((aLine,bLine) => (new Date(aLine.timestamp) > new Date(bLine.timestamp) ? 1 : -1) ); 
      this.fileData = data;

    },
    getTexts(){
      if(localStore.getItem('save_text_history')){
        //存在
        this.texts = JSON.parse(localStore.getItem('save_text_history'))
      }
    },
    openStoreList(){
      this.$emit('open',{
        pkId:this.chartPkId,
        goods:this.goodList.find(v => v.pkId == this.chartPkId).goods,
        period:this.period,
        saveId:this.saveId,
        id:this.id
      })
    }
  },
  unmounted: function () {
    this.removeChart();
    //清除定时器
    if(this.updateId){
      clearTimeout(this.updateId);
      this.updateId = undefined;
    }
  },
};
</script>
<style scoped>
.el-dropdown-link {
  cursor: pointer;
  color: var(--el-color-primary);
  display: flex;
  align-items: center;
}
.k-line-chart {
  width: 100%;
  flex-grow: 1;
  overflow: hidden;
}
.el-row{
  margin-bottom: 10px;
}
.el-col{
  margin-right: 20px;
}
.el-icon-close{
  padding: 0px 8px;
  line-height:100%;
  height:100%;
}
.option_item{
  display: flex;
  width: 100%;
}
.option_text{
  flex-grow: 1;
}
.option_icon{

}
.option_icon_start_filled{
  padding: 0px 11px;
  line-height:100%;
  height:100%;
}
.option_icon_start{
  padding: 0px 15px;
  line-height:100%;
  height:100%;
}
</style>